a tool for shared writing and social publishing
1import { z } from "zod";
2import { makeRoute } from "../lib";
3import type { Env } from "./route";
4import { AtUri } from "@atproto/syntax";
5import { getFactsFromHomeLeaflets } from "./getFactsFromHomeLeaflets";
6import { normalizeDocumentRecord } from "src/utils/normalizeRecords";
7import { ids } from "lexicons/api/lexicons";
8
9export type GetPublicationDataReturnType = Awaited<
10 ReturnType<(typeof get_publication_data)["handler"]>
11>;
12export const get_publication_data = makeRoute({
13 route: "get_publication_data",
14 input: z.object({
15 did: z.string(),
16 publication_name: z.string(),
17 }),
18 handler: async (
19 { did, publication_name },
20 { supabase }: Pick<Env, "supabase">,
21 ) => {
22 let pubLeafletUri;
23 let siteStandardUri;
24 if (/^(?!\.$|\.\.S)[A-Za-z0-9._:~-]{1,512}$/.test(publication_name)) {
25 pubLeafletUri = AtUri.make(
26 did,
27 ids.PubLeafletPublication,
28 publication_name,
29 ).toString();
30 siteStandardUri = AtUri.make(
31 did,
32 ids.SiteStandardPublication,
33 publication_name,
34 ).toString();
35 }
36 let { data: publication, error } = await supabase
37 .from("publications")
38 .select(
39 `*,
40 documents_in_publications(documents(
41 *,
42 comments_on_documents(count),
43 document_mentions_in_bsky(count)
44 )),
45 publication_subscriptions(*, identities(bsky_profiles(*))),
46 publication_domains(*),
47 leaflets_in_publications(*,
48 documents(*),
49 permission_tokens(*,
50 permission_token_rights(*),
51 custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*)
52 )
53 )`,
54 )
55 .or(
56 `name.eq."${publication_name}", uri.eq."${pubLeafletUri}", uri.eq."${siteStandardUri}"`,
57 )
58 .eq("identity_did", did)
59 .order("uri", { ascending: false })
60 .limit(1)
61 .single();
62
63 let leaflet_data = await getFactsFromHomeLeaflets.handler(
64 {
65 tokens:
66 publication?.leaflets_in_publications.map(
67 (l) => l.permission_tokens?.root_entity!,
68 ) || [],
69 },
70 { supabase },
71 );
72
73 // Pre-normalize documents from documents_in_publications
74 const documents = (publication?.documents_in_publications || [])
75 .map((dip) => {
76 if (!dip.documents) return null;
77 const normalized = normalizeDocumentRecord(
78 dip.documents.data,
79 dip.documents.uri,
80 );
81 if (!normalized) return null;
82 return {
83 uri: dip.documents.uri,
84 record: normalized,
85 indexed_at: dip.documents.indexed_at,
86 sort_date: dip.documents.sort_date,
87 data: dip.documents.data,
88 commentsCount: dip.documents.comments_on_documents[0]?.count || 0,
89 mentionsCount: dip.documents.document_mentions_in_bsky[0]?.count || 0,
90 };
91 })
92 .filter((d): d is NonNullable<typeof d> => d !== null);
93
94 // Pre-filter drafts (leaflets without published documents, not archived)
95 const drafts = (publication?.leaflets_in_publications || [])
96 .filter((l) => !l.documents)
97 .filter((l) => !(l as { archived?: boolean }).archived)
98 .map((l) => ({
99 leaflet: l.leaflet,
100 title: l.title,
101 permission_tokens: l.permission_tokens,
102 // Keep the full leaflet data for LeafletList compatibility
103 _raw: l,
104 }));
105
106 return {
107 result: {
108 publication,
109 documents,
110 drafts,
111 leaflet_data: leaflet_data.result,
112 },
113 };
114 },
115});